home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / Random2.0 / RandomPlot / Random.m < prev    next >
Text File  |  1995-06-12  |  9KB  |  385 lines

  1. //
  2. // Random
  3. //
  4. // Copyright (C) 1992 Contemporary Design Studios. All rights reserved.
  5. //
  6.  
  7.  
  8. #import "Random.h"
  9. #import <math.h>
  10. #import <stdlib.h>
  11. #import <stdio.h>
  12.  
  13.  
  14. @implementation Random
  15.  
  16.  
  17. //
  18. // version
  19. //
  20.  
  21. + (int)version
  22. {
  23.     return 3;                // Version 3 = Release 2.0.
  24. }
  25.  
  26. //
  27. // initEngineClass:
  28. //
  29.  
  30. - initEngineClass:aClass
  31. {
  32.     return [self initEngineInstance:[[aClass alloc] init]];
  33. }
  34.  
  35.  
  36. //
  37. // initEngineInstance:
  38. //
  39. // DESIGNATED INITIALIZER
  40. //
  41.  
  42. - initEngineInstance:anObject
  43. {
  44.     [super init];
  45.  
  46.     if(![anObject isKindOf:[RandomEngine class]]) {
  47.         //
  48.     // Can't do that!
  49.     //
  50.     }
  51.     
  52.     engine    = anObject;
  53.     engineClass    = [engine class];
  54.     unit    = [engineClass unit];
  55.     
  56.     bitbuffer    = (uchar *)malloc(unit);
  57.     bytebuffer    = (uchar *)malloc(unit);
  58.     curbit    = 0;
  59.     curbyte    = 0;
  60.     
  61.     [engine makeRandom:bitbuffer];            // Make some bits.
  62.     [engine makeRandom:bytebuffer];            // Make some bytes.
  63.     
  64.     return self;
  65. }
  66.  
  67.  
  68. //
  69. // rand
  70. //
  71.  
  72. - (ulong) rand
  73. {
  74.     ulong    temp = 0;
  75.     char    *ptr = (char *)(&temp);
  76.     ulong    i;
  77.     
  78.     for(i = 0; i < 4; i++) {
  79.         if(curbyte == unit) {                // i.e., bytebuffer empty.
  80.         [engine makeRandom:bytebuffer];
  81.         curbyte = 0;
  82.     }
  83.     ptr[i] = bytebuffer[curbyte];
  84.     curbyte++;
  85.     }
  86.     
  87.     return temp;
  88. }
  89.  
  90.  
  91. //
  92. // randMax:
  93. //
  94. // This isn't the most conservative algorithm possible. One could rotate bits and/or
  95. // bytes to try to come up with a value in range. However, the added complexity could
  96. // bog down the code even further. Therefore, until somebody proves that being more
  97. // conservative is useful, or a really clever, yet clear, algorithm presents itself,
  98. // this will suffice. Execution should be reasonably fast, and usage of random bits
  99. // and bytes should be reasonably light with this algorithm.
  100. //
  101.  
  102. - (ulong) randMax:(ulong)max
  103. {
  104.     ulong    ret        = 0;
  105.     ulong    *ptr        = &ret;
  106.     int        i;
  107.     
  108.     if(max == 0) {
  109.         ret = 0;
  110.     }
  111.     else if(max == 1) {                        // One bit needed.
  112.     if(curbit == (unit * 8)) {
  113.         [engine makeRandom:bitbuffer];
  114.         curbit = 0;
  115.     }
  116.     
  117.     ret = bitbuffer[curbit / 8] & (0x01 << (curbit % 8));
  118.     curbit++;
  119.     }
  120.     else if(max <= 0x000000ff) {                // One byte needed.
  121.         do {
  122.         if(curbyte == unit) {
  123.         [engine makeRandom:bytebuffer];
  124.         curbyte = 0;
  125.         }
  126.         ret = bytebuffer[curbyte];
  127.         curbyte++;
  128.     } while (ret > max);
  129.     }
  130.     else if(max <= 0x0000ffff) {                // Two bytes needed.
  131.         do {
  132.         for(i = 0; i < 2; i++) {
  133.         if(curbyte == unit) {
  134.             [engine makeRandom:bytebuffer];
  135.             curbyte = 0;
  136.         }
  137.         ptr[i + 2] = bytebuffer[curbyte];
  138.         curbyte++;
  139.         }
  140.     } while (ret > max);
  141.     }
  142.     else if(max <= 0x00ffffff) {                // Three bytes needed.
  143.         do {
  144.         for(i = 0; i < 3; i++) {
  145.         if(curbyte == unit) {
  146.             [engine makeRandom:bytebuffer];
  147.             curbyte = 0;
  148.         }
  149.         ptr[i + 1] = bytebuffer[curbyte];
  150.         curbyte++;
  151.         }
  152.     } while (ret > max);
  153.     } 
  154.     else {                            // Four bytes needed.
  155.         do {
  156.         for(i = 0; i < 4; i++) {
  157.         if(curbyte == unit) {
  158.             [engine makeRandom:bytebuffer];
  159.             curbyte = 0;
  160.         }
  161.         ptr[i] = bytebuffer[curbyte];
  162.         curbyte++;
  163.         }
  164.     } while (ret > max);
  165.     }
  166.     
  167.     return ret;
  168. }
  169.  
  170.  
  171. //
  172. // randMin:max:
  173. //
  174.  
  175. - (ulong)randMin:(ulong)min max:(ulong)max
  176. {
  177.     return min + [self randMax:(max - min)];
  178. }
  179.  
  180.  
  181. //
  182. // percent
  183. //
  184. // The information in the following exerpt was used to determine the
  185. // construction of a double-precision number with a value between 0.0 and
  186. // 1.0. It turns out to be easiest to construct one with a mantissa of:
  187. //
  188. // 1.rrrrrrrrrr rrrrrrrrrr rrrrrrrrrr rrrrrrrrrr rrrrrrrrrr rr
  189. // 
  190. // Where "r" stands for a random bit, and where the exponent is 0, i.e.
  191. // E is 1023, or 01111111111. Of course, the sign bit is 0. So, the
  192. // resulting number is:
  193. //
  194. // 00111111 1111rrrr rrrrrrrr rrrrrrrr rrrrrrrr rrrrrrrr rrrrrrrr rrrrrrrr
  195. //
  196. // Nicely enough, there is only 1 byte which is a mix of constant and
  197. // random bits. So, the trick is to generate 7 bytes of random data, and
  198. // then to overlay the constant 1111 into the high-order nibble of the
  199. // 2nd byte. Then, the first byte is just the constant 00111111.
  200. //
  201. // Of course, this is technically platform dependant, which is a no-no,
  202. // but I suppose if we move it to another machine, there may be a function
  203. // to convert from XDR format (which this is) to the local format (one can
  204. // hope), which would save us.
  205. //
  206. // -------------------------------- EXERPT --------------------------------
  207. // 
  208. // Network Working Group                             Sun Microsystems, Inc.
  209. // Request for Comments: 1014                                     June 1987
  210. // 
  211. // 
  212. //                XDR: External Data Representation Standard
  213. // 
  214. // ------------------------------------------------------------------------
  215. // 
  216. // 3.7 Double-precision Floating-point
  217. // 
  218. //    The standard defines the encoding for the double-precision floating-
  219. //    point data type "double" (64 bits or 8 bytes).  The encoding used is
  220. //    the IEEE standard for normalized double-precision floating-point
  221. //    numbers [3].  The standard encodes the following three fields, which
  222. //    describe the double-precision floating-point number:
  223. // 
  224. //       S: The sign of the number.  Values 0 and 1 represent positive and
  225. //          negative, respectively.  One bit.
  226. // 
  227. //       E: The exponent of the number, base 2.  11 bits are devoted to
  228. //          this field.  The exponent is biased by 1023.
  229. // 
  230. //       F: The fractional part of the number's mantissa, base 2.  52 bits
  231. //          are devoted to this field.
  232. // 
  233. //    Therefore, the floating-point number is described by:
  234. // 
  235. //          (-1)**S * 2**(E-Bias) * 1.F
  236. // 
  237. //    It is declared as follows:
  238. // 
  239. //          double identifier;
  240. // 
  241. //          +------+------+------+------+------+------+------+------+
  242. //          |byte 0|byte 1|byte 2|byte 3|byte 4|byte 5|byte 6|byte 7|
  243. //          S|    E   |                    F                        |
  244. //          +------+------+------+------+------+------+------+------+
  245. //          1|<--11-->|<-----------------52 bits------------------->|
  246. //          <-----------------------64 bits------------------------->
  247. //                                         DOUBLE-PRECISION FLOATING-POINT
  248. // 
  249. //    Just as the most and least significant bytes of a number are 0 and 3,
  250. //    the most and least significant bits of a double-precision floating-
  251. //    point number are 0 and 63.  The beginning bit (and most significant
  252. //    bit) offsets of S, E , and F are 0, 1, and 12, respectively.  Note
  253. //    that these numbers refer to the mathematical positions of the bits,
  254. //    and NOT to their actual physical locations (which vary from medium to
  255. //    medium).
  256. // 
  257. //    The IEEE specifications should be consulted concerning the encoding
  258. //    for signed zero, signed infinity (overflow), and denormalized numbers
  259. //    (underflow) [3].  According to IEEE specifications, the "NaN" (not a
  260. //    number) is system dependent and should not be used externally.
  261. // 
  262. // ------------------------------------------------------------------------
  263. // 
  264. //    [3]  "IEEE Standard for Binary Floating-Point Arithmetic", ANSI/IEEE
  265. //         Standard 754-1985, Institute of Electrical and Electronics
  266. //         Engineers, August 1985.
  267. // 
  268. // ------------------------------------------------------------------------
  269. // 
  270.  
  271. - (double)percent
  272. {
  273.     double    temp;
  274.     int        i;
  275.     
  276.     for(i = 1; i < 8; i++) {
  277.         if(curbyte == unit) {                // i.e., bytebuffer empty.
  278.         [engine makeRandom:bytebuffer];
  279.         curbyte = 0;
  280.     }
  281.     ((uchar *)(&temp))[i] = bytebuffer[curbyte];
  282.     curbyte++;
  283.     }
  284.     
  285.     ((ulong *)(&temp))[0] &= ((ulong)0x000fffff);
  286.     ((ulong *)(&temp))[0] |= ((ulong)0x3ff00000);
  287.     
  288.     return (temp - 1.0);
  289. }
  290.  
  291.  
  292. //
  293. // bool
  294. //
  295.  
  296. - (BOOL)bool
  297. {
  298.     BOOL    temp;
  299.     
  300.     if(curbit == (unit * 8)) {                // i.e., bitbuffer empty.
  301.     [engine makeRandom:bitbuffer];
  302.     curbit = 0;
  303.     }
  304.     
  305.     temp = bitbuffer[curbit / 8] & (0x01 << (curbit % 8));
  306.     curbit++;
  307.         
  308.     return (temp != 0);
  309. }
  310.  
  311.  
  312. //
  313. // randFunc:
  314. //
  315.  
  316. - (double)randFunc:(ddfunc)func
  317. {
  318.     return (*func)([self percent]);
  319. }
  320.  
  321.  
  322. //
  323. // read:
  324. //
  325.  
  326. - read:(NXTypedStream *)stream
  327. {
  328.     [super read:stream];
  329.     
  330.     //
  331.     // Read in the engine:
  332.     //
  333.     
  334.     NXReadTypes(stream, "@", &engine);
  335.     
  336.     //
  337.     // Set related instance variables:
  338.     //
  339.     
  340.     engineClass    = [engine class];
  341.     unit    = [engineClass unit];
  342.     bitbuffer    = (uchar *)malloc(unit);
  343.     bytebuffer    = (uchar *)malloc(unit);
  344.     curbit    = 0;
  345.     curbyte    = 0;
  346.     
  347.     //
  348.     // Read in the buffers:
  349.     //
  350.     
  351.     [engine makeRandom:bitbuffer];            // Make some bits.
  352.     [engine makeRandom:bytebuffer];            // Make some bytes.
  353.     
  354.     return self;
  355. }
  356.  
  357.  
  358. //
  359. // write:
  360. //
  361.  
  362. - write:(NXTypedStream *)stream
  363. {
  364.     [super write:stream];
  365.     
  366.     //
  367.     // Write out the engine:
  368.     //
  369.     
  370.     NXWriteTypes(stream, "@", &engine);
  371.     
  372.     //
  373.     // Write out the buffers:
  374.     //
  375.     
  376.     return self;
  377. }
  378.  
  379.  
  380. @end
  381.  
  382.  
  383. //
  384. // End of file.
  385. //